package battleModel;

import java.awt.Image;
import java.awt.Point;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;

import javax.imageio.ImageIO;

/**
 * 
 * Tank class, AI to follow... Obstacle Attributes: health=100, damageable=true,
 * location=in constructor, image=in constructor Other attributes: angle=in
 * constructor, speed=in constructor (4 is average, 0-10 is immobile to fast);
 * 
 * Default Tank, as a result of Tank() constructor has:
 * angle=0,speed=3,image=default Tank, location=(300,300)
 */
// added extends Obstacle
public class Tank extends Obstacle implements Serializable {

	private static final long serialVersionUID = 1L;
	
	//Player Information
	private String name, color, difficulty;
	private double speed;
	//Campaign Specific
	private int maxLevel;
	private int[] levelScore;
	 
	
	private transient Perimeter perimeter;
	private transient Image turretImg, tankImg;
	private transient AffineTransform tankAffine, turretAffine;
	private transient double tankAngle, turretAngle;
	private transient final double tankCenterX = 31.5, tankCenterY = 31.5;
	private transient final double turretCenterX = 31.5, turretCenterY = 30.5;

	public Tank() {

		super(100, true, new Point(300, 300), null);

		try {
			tankImg = ImageIO.read(new File("images/tanks/TankSprite.png"))
					.getSubimage(0, 125, 63, 63);
			turretImg = ImageIO.read(new File("images/tanks/TankSprite.png"))
					.getSubimage(0, 375, 63, 63);
		} catch (IOException e) {
			e.printStackTrace();
		}

		perimeter = new Perimeter(5, 14, 52, 33);

		tankAffine = new AffineTransform();
		turretAffine = new AffineTransform();
		tankAffine.translate(300, 300);
		turretAffine.translate(300, 300);

		speed = 3.0;
		tankAngle = 0;
		turretAngle = 0;
		name = "";
		color = "";
		maxLevel = 5; //DEFAULT = 1

		levelScore = new int[20];

		// Set all scores to 0
		for (int i = 0; i < CampaignModel.LEVELS; i++)
			levelScore[i] = 0;
	}

	/**
	 * 
	 * @param i
	 *            Image of this Tank, this will be the tank with turret next to
	 *            it. but is currently the TankSprite
	 * @param l
	 *            initial location as a Point
	 * @param slope
	 *            initial Slope as a double
	 * @param speed
	 *            initial speed as an int (3 is average, 0-10 is immobile to
	 *            fast)
	 */
	public Tank(Image i, Point l, double angle, int speed) {
		super(100, true, l, i);
		tankAngle = angle;
		turretAngle = angle;
		this.speed = speed;

		tankImg = ((BufferedImage) i).getSubimage(0, 125, 63, 63);
		turretImg = ((BufferedImage) i).getSubimage(0, 375, 63, 63);

		perimeter = new Perimeter(5, 14, 52, 33);

		tankAffine = new AffineTransform();
		tankAffine.translate(l.getX(), l.getY());
		tankAffine.rotate(angle, tankCenterX, tankCenterY);

		turretAffine = new AffineTransform();
		turretAffine.translate(l.getX(), l.getY());
		turretAffine.rotate(angle, turretCenterX, turretCenterY);

		// your other code from default constructor
		name = "";
		color = "";

		levelScore = new int[20];

		// All other levels locked by default,
		for (int j = 0; j < 20; j++)
			levelScore[j] = 0;
	}

	/**
	 * Set the name of the player, will be the file name which the player's
	 * profile is saved
	 * 
	 * @param name
	 *            Name of the Player
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Get the color of the tank
	 * 
	 * @return 8 different colors (Red-Purple, White, Black)
	 */
	public String getColor() {
		return color;
	}

	/**
	 * Get the name of the tank
	 * 
	 * @return
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the color of the players tank
	 * 
	 * @param color
	 *            - string value representing the color
	 */
	public void setColor(String color) {
		this.color = color;
	}

	/**
	 * Returns the difficulty of the AI on this
	 * player's profile
	 * @return
	 */
	public String getDifficulty(){
		return difficulty;
	}
	
	/**
	 * Set the difficulty of the AI
	 * @param difficulty - Set under the Difficulty enum class
	 */
	public void setDifficulty(Difficulty difficulty){
		this.difficulty = difficulty.toString();
	}
	/**
	 * Get the speed of the tank
	 * 
	 * @return
	 */
	public double speed() {
		return speed;
	}

	/**
	 * Set the speed of the tank
	 * 
	 * @param speed
	 *            - must be a positive integer
	 */
	public void setSpeed(double speed) {
		this.speed = speed;
	}

	/**
	 * Increase the speed of the player's tank with an increment
	 * 
	 * @param inc
	 *            - increments the current speed
	 */
	public void increaseSpeed(double inc) {
		speed += inc;
	}

	/**
	 * Set the current level chosen by the player
	 * 
	 * @param level
	 *            The level set to be played
	 */
	public void setMaxLevel(int level) {
		maxLevel = level;
	}

	/**
	 * Check if level passed as argument is locked to the player
	 * 
	 * @param level
	 *            - level being checked if locked (1-20)
	 * @return true if locked, false if not locked
	 */
	public int getMaxLevel() {
		return maxLevel;
	}

	/**
	 * Get player's score of the level specified
	 * 
	 * @param level
	 *            The level which to get the score from (1-20 inclusive)
	 * @return score of the level passed (0-1000)
	 */
	public int getLevelScore(int level) {
		return levelScore[level - 1];
	}

	/**
	 * Set the player's score of the level passed
	 * 
	 * @param level
	 *            The level to set the score
	 * @param score
	 *            The player's score of the level passed
	 */
	public void setLevelScore(int level, int score) {

		if (level > 1 && level < 20) {
			if (score > 1000) {
				levelScore[level - 1] = 1000;
				System.out.println("Score exceeds 1000");
			} else
				levelScore[level - 1] = score;
		}else 
			System.out.println("Invalid Level");
	}

	/**
	 * Get the player's tank angle
	 * 
	 * @return
	 */
	public double getTankAngle() {
		return tankAngle;
	}

	/**
	 * Get the player's turret angle
	 * 
	 * @return
	 */
	public double getTurretAngle() {
		return turretAngle;
	}

	/**
	 * Get the Tank's AffineTransform Object
	 * @return
	 */
	public AffineTransform getTankAffine() {
		return tankAffine;
	}

	/**
	 * Get the Tank's turret AffineTransform Object
	 * @return
	 */
	public AffineTransform getTurretAffine() {
		return turretAffine;
	}

	/**
	 * Get the the shape of the tank
	 * 
	 * @return - the specified rectangle shape of the tank
	 */
	public Shape getCollisionShape() {
		return perimeter.getRect();
	}

	/**
	 * Scale the tank to the appropriate size
	 * 
	 * @param xScale - scale to the new value of x
	 * @param yScale - scale to the new value of y
	 */
	public void scale(double xScale, double yScale) {
		tankAffine.scale(xScale, yScale);
		turretAffine.scale(xScale, yScale);
	}

	/**
	 * Move the tank forward in the positive x direction
	 */
	public void moveForward() {
		tankAffine.translate(speed, 0);
		turretAffine.translate(speed * Math.cos(tankAngle - turretAngle), speed
				* Math.sin(tankAngle - turretAngle));
	}

	/**
	 * Move the tank backward in the negative x direction
	 */
	public void moveBackward() {
		tankAffine.translate(-speed / 2, 0);
		turretAffine.translate(
				(-speed / 2) * Math.cos(tankAngle - turretAngle), (-speed / 2)
						* Math.sin(tankAngle - turretAngle));
	}

	/**
	 * Turn the tank in the counter-clockwise direction
	 */
	public void turnLeft() {
		tankAffine.rotate(-Math.PI / 32, 31.25, 31.25);
		tankAngle -= Math.PI / 32;
	}

	/**
	 * Turn the tank in the clockwise direction
	 */
	public void turnRight() {
		tankAffine.rotate(Math.PI / 32, 31.25, 31.25);
		tankAngle += Math.PI / 32;
	}

	/**
	 * Turn the turret in the counter-clockwise direction
	 */
	public void turretTurnLeft() {
		turretAffine.rotate(-Math.PI / 32, 31, 30.5);
		turretAngle -= Math.PI / 32;
	}
	
	/**
	 * Turn the turret in the clockwise direction
	 */
	public void turretTurnRight() {
		turretAffine.rotate(Math.PI / 32, 31, 30.5);
		turretAngle += Math.PI / 32;
	}

	/**
	 * Reposition the turret angle relative to the mouse position
	 * @param e
	 */
	public void adjustTurretFromMouse(MouseEvent e) {
		double x, y, tempAngle = turretAngle;
		y = e.getY() - turretCenterY - turretAffine.getTranslateY();
		x = e.getX() + turretCenterX - turretAffine.getTranslateX();
		turretAngle = Math.atan(y / x);
		if (x < 0)
			turretAngle -= Math.PI;

		turretAffine.rotate(turretAngle - tempAngle, 31, 30.5);
	}

	/**
	 * Get the image of the turret
	 * @return
	 */
	public Image getTurretImage() {
		return turretImg;
	}

	/**
	 * Get the image of the tank body
	 * @return
	 */
	public Image getTankImage() {
		return tankImg;
	}
}
